#include <fstream>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include "testadorAresta.h"

using std::cout;
using std::endl;
using std::ifstream;
using std::ios;
using std::string;
using std::vector;

void ReadInstance(char* file_path, Instancia* inst) {
  Edge aresta_aux;
  Node nodo_aux;
  ifstream infile;
  infile.open(file_path);
  char codigo;

  if (!inst->aresta.empty() || !inst->nodo.empty()) {
    inst->aresta.clear();
    inst->nodo.clear();
  }

  while (infile.good()){
  infile >> codigo;
  if (codigo == 'c'){
     char trash[256];
     infile.getline(trash, 256);
     delete trash;
    }else if (codigo == 'p') {
      infile >> inst->tipo_de_problema;
      infile >> inst->num_nodos;
      infile >> inst->num_arestas;
    } else if (codigo == 'e') {
      infile >> aresta_aux.n1;
      infile >> aresta_aux.n2;
      infile >> codigo;
      if (codigo == 'c' || codigo == 'e' || codigo == 'p' || codigo == 'n') {
        aresta_aux.d = 1;
        infile.unget();
      } else {
        infile >> aresta_aux.d;
      }
      inst->aresta.push_back(aresta_aux);
    } else if (codigo == 'n') {
      infile >> nodo_aux.n1;
      infile >> nodo_aux.c1;
      inst->nodo.push_back(nodo_aux);
    } else {
      cout << "problema com a instancia. ERRO.";
      break;
    }
  }
  infile.close();
}

void ReadSolution (char* file_path, Solucao* sol){

  ifstream infile;
  infile.open(file_path);
  vector<int> aux;
  char* token;

  if (infile.is_open() && infile.good()) {
    char line[256];
    infile.getline(line, 256);
    token = strtok(line, " ,\n");

    sol->num_cores = atoi(token);
    token = strtok (NULL, " ,\n");
    sol->custo = atoi(token);
    token = strtok (NULL, " ,\n");

    delete line;

    for (int i = 0; i < sol->num_cores; i++) {
      char line[256];
      infile.getline(line, 256);
      token = strtok(line, " ,\n");
      while (token != NULL) {
        aux.push_back(atoi(token));
        token = strtok (NULL, " ,");
      }
      sol->nodo.push_back(aux);
      aux.clear();
      delete line;
    }
  } else {
    cout << "Erro!! Nao achei o arquivo." << endl;
  }
  infile.close();
}

bool InstanceSizeTest(const Instancia& inst) {
  if (inst.num_arestas == inst.aresta.size() &&
      inst.num_nodos == inst.nodo.size()) {
    return true;
  } else {
    return false;
  }
}

bool SolutionSizeTest(const Solucao& sol) {
  if (sol.num_cores == sol.nodo.size()){
    int j = 0;
    for (int i = 0; i < sol.num_cores; i++) {
      if (sol.nodo[i][0] == sol.nodo[i].size() - 1) {
        j++;
      }
    }
    if (j == sol.num_cores) {
      return true;
    }
  } else {
    return false;
  }
}

bool InstanceRedundant(const Instancia& inst) {
  for (int i = 0; i < inst.nodo.size() - 1; i++) {
    for (int j = 1; j < inst.nodo.size() - i; j++) {
      if (inst.nodo[i].n1 == inst.nodo[i+j].n1) {
        return false;
      }
    }
  }
  for (int i = 0; i < inst.aresta.size() -1 ; i++) {
    for (int j = 1; j < inst.aresta.size() - i; j++) {
      if (inst.aresta[i].n1 == inst.aresta[i+j].n1 &&
          inst.aresta[i].n2 == inst.aresta[i+j].n2) {
        return false;
      }
    }
  }
  return true;
}

bool SolutionRedundant(const Solucao& sol) {
  for (int i = 0; i < sol.num_cores; i++) {
    for (int j = 1; j < sol.nodo[i].size() - 1; j++) {
      for (int k = 1; k < sol.nodo[i].size() - j; k++) {
        if (sol.nodo[i][j] == sol.nodo[i][j+k]) {
          return false;
        }
      }
    }
  return true;
  }
}

void PrintInstance(const Instancia& inst) {
  cout << inst.tipo_de_problema << ", "
       << inst.num_nodos << ", "
       << inst.num_arestas << ", " << endl;
  for (int i = 0; i < inst.nodo.size(); i++) {
    cout << inst.nodo[i].n1 << ", "
         << inst.nodo[i].c1 << endl;
  }
  for (int j = 0; j < inst.aresta.size(); j++) {
    cout << inst.aresta[j].n1 << ", "
         << inst.aresta[j].n2 << ", "
         << inst.aresta[j].d << endl;
  }
}

void PrintSolution(const Solucao& sol) {
  cout << endl << sol.num_cores << ", "
       << sol.custo << endl;
  for (int i = 0; i < sol.num_cores ; i++) {
    cout << sol.nodo[i][0] << endl;
    for (int j = 1; j < sol.nodo[i].size(); j++) {
      cout << sol.nodo[i][j] << " " ;
    }
    cout << endl;
  }
}

bool IsFeasible(const Solucao& sol, const Instancia& inst) {
  if (InstanceSizeTest(inst) && InstanceRedundant(inst) &&
      SolutionSizeTest(sol) && SolutionRedundant(sol)) {
    for (int i = 0; i < sol.nodo.size(); i++) {
      for (int j = 1; j < sol.nodo[i].size(); j++) {
        for (int k = 0; k < inst.aresta.size(); k++) {
          if (sol.nodo[i][j] == inst.aresta[k].n1 ||
              sol.nodo[i][j] == inst.aresta[k].n2) {

              if (sol.nodo[i][j] != inst.aresta[k].n1) {
                for (int l = 1; l < sol.nodo[i].size(); l++) {
                  if (inst.aresta[k].n1 == sol.nodo[i][l]) {
                    return false;
                  }
                }
              } else {
                for (int l = 1; l < sol.nodo[i].size(); l++) {
                  if (inst.aresta[k].n2 == sol.nodo[i][l]) {
                    return false;
                  }
                }
              }
          }
        }
      }
    }
    return true;
  } else {
    return false;
  }
}

void PrintResults(const Solucao& sol, const Instancia& inst) {
  if (IsFeasible(sol,inst)) {
    cout << "Is Feasible. " << endl;
  } else {
    cout << "Not Feasible. " << endl;
  }
}
